#include <iostream>
#include <fstream>
#include <sstream>
#include <algorithm>
#include <unistd.h>
#include "jsonconfig.h"
#include "../json11/json11.hpp"
using namespace std;
using namespace json11;
BridgeConfig config;

static void log(string msg, int level)
{
    if (!config.debuglog)
        return;
    if (level == 0 && level >= config.loglevel)
        cout << "\033[36m[jsonconfig]\033[0m" << msg << endl;
    else if (level == 1 && level >= config.loglevel)
        cout << "\033[36m[jsonconfig]\033[0m"
             << "\033[36m" << msg << "\033[0m" << endl;
    else if (level >= 2)
        cout << "\033[36m[jsonconfig]\033[0m"
             << "\033[31m" << msg << "\033[0m" << endl;
}

/**
 * @brief 转换JSON文件为Json对象
 * 
 * @param file 文件名
 * @return Json 转换结果，若为空则表示有误
 */
static Json phrasejsonfile(string file)
{
    Json json_obj;
    ifstream jsonfile(file);
    stringstream ss;
    ss << jsonfile.rdbuf();
    string jsonstr = ss.str();
    if (jsonstr.empty())
    {
        log("json file not correct.", 2);
        return json_obj;
    }
    string err;
    json_obj = Json::parse(jsonstr, err, JsonParse::STANDARD);
    if (json_obj.is_null())
    {
        log(err, 2);
        return json_obj;
    }
    return json_obj;
}

/**
 * @brief 初始化默认配置
 * 
 */
void defaultconfig()
{
    config.modbusfile = "modbus.json";

    config.rtuconfig.rtuport = "/dev/ttymxc1";
    config.rtuconfig.baudrate = 115200;
    config.rtuconfig.parity = 'N';
    config.rtuconfig.databit = 8;
    config.rtuconfig.stopbit = 1;

    config.tcpconfig.port = 1502;

    config.bridgeconfig.looptimeout = 100;
    config.bridgeconfig.pollingtimeout = 500;
    config.bridgeconfig.requesttimeout = 500;
    config.bridgeconfig.maxnb = 32;
    config.bridgeconfig.commtimeout = 200;

    config.debuglog = true;
    config.loglevel = 0;
}

/**
 * @brief 根据Json文件配置桥接器参数
 * 
 * @param file 配置文件
 * @return true 无误
 * @return false 文件读取错误
 */
bool BridgeCfg(string file)
{
    defaultconfig();
    auto json_obj = phrasejsonfile(file);
    if (json_obj.is_null())
        return false;
    if (!json_obj["modbusfile"].is_null())
        config.modbusfile = json_obj["modbusfile"].string_value();
    if (!json_obj["rtuconfig"]["rtuport"].is_null())
        config.rtuconfig.rtuport = json_obj["rtuconfig"]["rtuport"].string_value();
    if (!json_obj["rtuconfig"]["baudrate"].is_null())
        config.rtuconfig.baudrate = json_obj["rtuconfig"]["baudrate"].int_value();
    if (!json_obj["rtuconfig"]["parity"].is_null())
        config.rtuconfig.parity = json_obj["rtuconfig"]["parity"].string_value()[0];
    if (!json_obj["rtuconfig"]["stopbit"].is_null())
        config.rtuconfig.stopbit = json_obj["rtuconfig"]["stopbit"].int_value();
    if (!json_obj["rtuconfig"]["databit"].is_null())
        config.rtuconfig.databit = json_obj["rtuconfig"]["databit"].int_value();
    if (!json_obj["tcpconfig"]["port"].is_null())
        config.tcpconfig.port = json_obj["tcpconfig"]["port"].int_value();
    if (!json_obj["bridgeconfig"]["looptimeout"].is_null())
        config.bridgeconfig.looptimeout = json_obj["bridgeconfig"]["looptimeout"].int_value();
    if (!json_obj["bridgeconfig"]["requesttimeout"].is_null())
        config.bridgeconfig.requesttimeout = json_obj["bridgeconfig"]["requesttimeout"].int_value();
    if (!json_obj["bridgeconfig"]["pollingtimeout"].is_null())
        config.bridgeconfig.pollingtimeout = json_obj["bridgeconfig"]["pollingtimeout"].int_value();
    if (!json_obj["bridgeconfig"]["maxnb"].is_null())
        config.bridgeconfig.maxnb = json_obj["bridgeconfig"]["maxnb"].int_value();
    if (!json_obj["bridgeconfig"]["commtimeout"].is_null())
        config.bridgeconfig.commtimeout = json_obj["bridgeconfig"]["commtimeout"].int_value();
    if (!json_obj["debuglog"].is_null())
        config.debuglog = json_obj["debuglog"].bool_value();
    if (!json_obj["loglevel"].is_null())
        config.loglevel = json_obj["loglevel"].int_value();
    return true;
}

/**
 * @brief 获取JSON文件定义的寄存器地址集合
 * 
 * @return true 无误
 * @return false 文件不存在或语法错误
 */
bool ModbusJsonConfig()
{
    auto json_obj = phrasejsonfile(config.modbusfile);
    if (json_obj.is_null())
        return false;
    auto devices = json_obj["network"][0]["device"].array_items();
    if (devices.empty())
    {
        log("no devices info.", 2);
        return false;
    }
    for (uint16_t i = 0; i < devices.size(); i++)
    {
        //获取所有需要缓存的点信息并存储为<slave,func,addr>
        uint8_t slave = devices[i]["slave"].int_value();
        map<uint8_t, vector<uint16_t>> newslave;
        config.points.insert(pair<uint8_t, map<uint8_t, vector<uint16_t>>>(slave, newslave));
        ;
        auto points = devices[i]["point"].array_items();
        auto regmemory = config.points.find(slave);
        for (uint16_t j = 0; j < points.size(); j++)
        {
            uint8_t func = points[j]["func"].int_value();
            uint16_t addr;
            if(points[j]["addr"].is_string())
            {
                auto addr_str = points[j]["addr"].string_value();
                addr = stoi(addr_str,0,16);
            }
            else
                addr = points[j]["addr"].int_value();
            auto func_mem = regmemory->second.find(func);
            if (func_mem == regmemory->second.end())
            {
                vector<uint16_t> addrlist;
                addrlist.push_back(addr);
                regmemory->second.insert(pair<uint8_t, vector<uint16_t>>(func, addrlist));
            }
            else
                func_mem->second.push_back(addr);
        }
    }
    for (auto slave = config.points.begin(); slave != config.points.end(); slave++)
    {
        for (auto func = slave->second.begin(); func != slave->second.end(); func++)
        {
            //对寄存器地址排序并去重
            sort(func->second.begin(), func->second.end());
            func->second.erase(unique(func->second.begin(), func->second.end()), func->second.end());
        }
    }
    return true;
}

/**
 * @brief 获取JSON文件定义的Bridge配置
 * 
 * @param file 文件名
 * @return true 无误
 * @return false 文件不存在或语法错误
 */
bool BridgeJsonConfig(string file)
{
    #define MAX_SIZE 512
    char current_absolute_path[MAX_SIZE];
    //获取当前程序绝对路径
    int cnt = readlink("/proc/self/exe", current_absolute_path, MAX_SIZE);
    if (cnt < 0 || cnt >= MAX_SIZE)
    {
        log("Path Read Error",2);
        exit(-1);
    }
    //获取当前目录绝对路径，即去掉程序名
    int i;
    for (i = cnt; i >= 0; --i)
    {
        if (current_absolute_path[i] == '/')
        {
            current_absolute_path[i + 1] = '\0';
            break;
        }
    }
    file = current_absolute_path + file;
    BridgeCfg(file);
    log("bridge json config init.", 0);
    bool res = ModbusJsonConfig();
    return res;
}